 /*******************************************************************************
  * Copyright (c) 2005 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
  * http://www.eclipse.org/legal/epl-v10.html
  *
  * Contributors:
  * IBM Corporation - initial API and implementation
  *******************************************************************************/
 package org.eclipse.ui.internal;

 import org.eclipse.swt.SWT;
 import org.eclipse.swt.graphics.Point;

 public final class IntAffineMatrix {
     
     public static final IntAffineMatrix IDENTITY = new IntAffineMatrix(1, 0, 0, 0, 1, 0);
     public static final IntAffineMatrix ROT_90 = new IntAffineMatrix(0, -1, 0, 1, 0, 0);
     public static final IntAffineMatrix ROT_180 = new IntAffineMatrix(-1, 0, 0, 0, -1, 0);
     public static final IntAffineMatrix ROT_270 = new IntAffineMatrix(0, 1, 0, -1, 0, 0);
     public static final IntAffineMatrix FLIP_XAXIS = new IntAffineMatrix(1, 0, 0, 0, -1, 0);
     public static final IntAffineMatrix FLIP_YAXIS = new IntAffineMatrix(-1, 0, 0, 0, 1, 0);
     
     int m11;
     int m12;
     int m13;
     int m21;
     int m22;
     int m23;
     
     public IntAffineMatrix() {
         this(1, 0, 0, 0, 1, 0);
     }
     
     public IntAffineMatrix(int _m11, int _m12, int _m13, int _m21, int _m22, int _m23) {
         m11 = _m11;
         m12 = _m12;
         m13 = _m13;
         m21 = _m21;
         m22 = _m22;
         m23 = _m23;
     }
     
     public IntAffineMatrix(IntAffineMatrix toCopy) {
         this(toCopy.m11, toCopy.m12, toCopy.m13, toCopy.m21, toCopy.m22, toCopy.m23);
     }
     
     public IntAffineMatrix inverse() {
         int det = det();
         
         return new IntAffineMatrix(
                 m22 / det, -m12 / det, (m12 * m23 - m22 * m13) / det,
                 -m21 / det, m11 / det, (m21 * m13 - m11 * m23) / det);
     }
     
     /**
      * Returns a rotation matrix that would make a vector pointing directly up
      * point in the given direction.
      *
      * @param swtDirectionConstant
      * @return a rotation matrix that would make a vector pointing directly up
      * point in the given direction
      */
     public static IntAffineMatrix getRotation(int swtDirectionConstant) {
         switch(swtDirectionConstant) {
         case SWT.RIGHT: return ROT_90;
         case SWT.BOTTOM: return ROT_180;
         case SWT.LEFT: return ROT_270;
         }
         
         return IDENTITY;
     }
     
     public int det() {
         return m11 * m22 - m12 * m21;
     }
     
     public static IntAffineMatrix translation(int x, int y) {
         return new IntAffineMatrix(1, 0, x, 0, 1, y);
     }
  
     public static IntAffineMatrix translation(Point vector) {
         return new IntAffineMatrix(1, 0, vector.x, 0, 1, vector.y);
     }
     
     /**
      * Returns a new matrix formed by applying the argument transformation followed
      * by the receiver. The receiver and the argument are unmodified.
      *
      * @param matrix matrix to transform
      * @return a new transformed matrix
      */
     public IntAffineMatrix multiply(IntAffineMatrix m) {
         IntAffineMatrix result = new IntAffineMatrix(
                 m11 * m.m11 + m12 * m.m21,
                 m11 * m.m12 + m12 * m.m22,
                 m11 * m.m13 + m12 * m.m23 + m13,
                 m21 * m.m11 + m22 * m.m21,
                 m21 * m.m12 + m22 * m.m22,
                 m21 * m.m13 + m22 * m.m23 + m23
         );
         return result;
     }
     
 // /**
 // * Applies the reciever's transformation to the given matrix. For example, if the
 // * argument is a translation and the reciever is a rotation about the origin,
 // * the argument will become a translation followed by a rotation about the origin.
 // *
 // * @param m matrix to be modified
 // */
 // public void transform (IntAffineMatrix m) {
 // m.m11 = m11 * m.m11 + m12 * m.m21;
 // m.m12 = m11 * m.m12 + m12 * m.m22;
 // m.m13 = m11 * m.m13 + m12 * m.m23 + m13;
 // m.m21 = m21 * m.m11 + m22 * m.m21;
 // m.m22 = m21 * m.m12 + m22 * m.m22;
 // m.m23 = m21 * m.m13 + m22 * m.m23 + m23;
 // }

     /**
      * Copies and transforms a set of points from the source shape to the dest
      *
      * @param source source shape (alternating x and y values, starting with an x value)
      * @param sourcePos index of the first point in the source array to transform (the value
      * 3 indicates the 3rd x, y pair in the array, which is at position 6)
      * @param dest destination shape (alternating x and y values, starting with an x value). A
      * portion of this array will be overwritten.
      * @param destPos first point to overwrite in the dest array (each x, y pair is considered
      * 1 position)
      * @param length number of points to copy
      */
     public void transform(int[] source, int sourcePos, int[] dest, int destPos, int length) {
         int nextSrc = sourcePos * 2;
         int nextDest = destPos * 2;
         for(int i = 0; i < length; i++) {
             int sourcex = source[nextSrc++];
             int sourcey = source[nextSrc++];
             
             dest[nextDest++] = getx(sourcex, sourcey);
             dest[nextDest++] = gety(sourcex, sourcey);
         }
     }

     /**
      * @param sourcex
      * @param sourcey
      * @return
      */
     public int gety(int sourcex, int sourcey) {
         return sourcex * m21 + sourcey * m22 + m23;
     }

     /**
      * @param sourcex
      * @param sourcey
      * @return
      */
     public int getx(int sourcex, int sourcey) {
         return sourcex * m11 + sourcey * m12 + m13;
     }
     
     public Shape transform(Shape toTransform) {
         int[] newArray = new int[toTransform.used];
         transform(toTransform.data, 0, newArray, 0, toTransform.used / 2);
         return new Shape(newArray);
     }
     
     /**
      * Transforms a point, returning the newly transformed point. The original
      * point is unmodified.
      *
      * @param toTransform point to transform
      * @return trantsformed point
      */
     public Point multiply(Point toTransform) {
         return new Point(toTransform.x * m11 + toTransform.y * m12 + m13,
                 toTransform.x * m21 + toTransform.y * m22 + m23);
     }
 }

